﻿#include "ICPService.h"

#include "ICPRule.h"

using namespace concurrency;

ICPService::ICPService() {}

ICPService::~ICPService() {}

SchPairing* ICPService::convertPairing(string name, vector<SchLeg*> legs, string baseCode) {
    SchPairing* newPairing = new SchPairing(baseCode);

    time_t date;
    SchDuty* newDuty = NULL;
    vector<SchDuty*> dutys;
    for (int i = 0; i < legs.size(); i++) {
        if (newDuty == NULL || legs[i]->getDate() != date) {
            date = legs[i]->getDate();

            newDuty = new SchDuty(date, 1);
            newDuty->pushLeg(legs[i]);
            dutys.push_back(newDuty);
            continue;
        }

        if (legs[i]->getDate() == date) {
            newDuty->pushLeg(legs[i]);
        }
    }

    vector<SchDuty*> restDutys;
    for (int i = 0; i < dutys.size() - 1; i++) {
        if (dutys[i]->getDate() + DAY_SECONED_DEFINE != dutys[i]->getDate()) {
            time_t bgnDate = dutys[i]->getDate() + DAY_SECONED_DEFINE;
            time_t endDate = dutys[i + 1]->getDate();
            BasAirport* airport = dutys[i]->getArr();
            for (time_t j = bgnDate; j < endDate; j = j + DAY_SECONED_DEFINE) {
                SchDuty* newDuty = new SchDuty(j, 1);
                newDuty->setType(DUTY_REST);
                newDuty->setAirport(airport);
                restDutys.push_back(newDuty);
            }
        }
    }

    dutys.insert(dutys.end(), restDutys.begin(), restDutys.end());
    sort(dutys.begin(), dutys.end(), SchDuty::cmpByTime);

    for (int i = 0; i < dutys.size(); i++) {
        newPairing->pushDuty(dutys[i]);
    }

    return newPairing;
}

BasAirport* ICPService::getAirport(string code3) {
    for (int i = 0; i < _airportList.size(); i++) {
        if (_airportList[i]->getCode3() == code3) {
            return _airportList[i];
        }
    }
    return NULL;
}

SchLeg* ICPService::getLeg(string flightId) {
    for (int i = 0; i < _legList.size(); i++) {
        if (_legList[i]->getFlightId() == flightId) {
            return _legList[i];
        }
    }
    return NULL;
}

SchLeg* ICPService::newVALeg(SchLeg* leg) {
    if (leg == NULL)
        return NULL;

    string flightId = leg->getFlightId();
    string fltNo = leg->getFlightNo();
    BasAirport* dep = leg->getDep();
    BasAirport* arr = leg->getArr();
    time_t std = leg->getStd();
    time_t sta = leg->getSta();
    time_t theDate = leg->getDate();
    string acType = leg->getAcType();
    string acTypeCrew = leg->getAcTypeCrew();
    string acReg = leg->getAcReg();
    D_OR_I dori = leg->getDorI();
    string crewOwner = leg->getCrewOwner();
    SchLeg* vaLeg = new SchLeg(LEG_VA, flightId, fltNo, dep, arr, std, sta, theDate, acType, acTypeCrew, acReg, dori,
                               P_OR_C::P, 0, REST_LEVEL_NIL, crewOwner);
    time_t signIn = ICPUtility::signIn;
    time_t signOut = ICPUtility::signOut;
    time_t dhHotelStd = ICPUtility::signIn;
    time_t dhStaHotel = ICPUtility::signOut;
    if (dep->getBasAirportNight() != NULL) {
        signIn = dep->getBasAirportNight()->getDhSignIn();
        dhHotelStd = dep->getBasAirportNight()->getDhHotelStd();
    }
    if (arr->getBasAirportNight() != NULL) {
        signOut = arr->getBasAirportNight()->getDhSignOut();
        dhStaHotel = arr->getBasAirportNight()->getDhStaHome();
    }
    vaLeg->setSignIn(vaLeg->getStd() - signIn);
    vaLeg->setSignOut(vaLeg->getSta() + signOut);
    vaLeg->setEndRestTime(vaLeg->getStd() - dhHotelStd);
    vaLeg->setBgnRestTime(vaLeg->getSta() + dhStaHotel);
    return vaLeg;
}

SchLeg* ICPService::getSolnDeadheadLeg(string flightId) {
    for (int i = 0; i < _slnDeadheadLegList.size(); i++) {
        if (_slnDeadheadLegList[i]->getFlightId() == flightId) {
            return _slnDeadheadLegList[i];
        }
    }
    return NULL;
}

void ICPService::init() {
    // initResLimit();
    genDutyList();
    initNodeList();
    genPairingListByPattern();
}

void ICPService::initResLimit() {
    vector<string> acTypeCrews;
    if (ICPUtility::moduleFlag == "A") {
        acTypeCrews.push_back("XXX");
    } else {
        for (auto it : _legList) {
            if (it->getLegType() != LEG_REGULAR)
                continue;
            if (it->getAcTypeCrew().empty())
                continue;

            if (find(acTypeCrews.begin(), acTypeCrews.end(), it->getAcTypeCrew()) == acTypeCrews.end()) {
                acTypeCrews.push_back(it->getAcTypeCrew());
            }
        }
    }
    int N = acTypeCrews.size();

    vector<string> combs;
    genAcTypeCrewComb(acTypeCrews, N, combs);
    set<string> acTypeCrewCombs;
    for (auto it1 : combs) {
        set<string> setComb;
        for (auto it2 : splitString(it1, "/")) {
            setComb.insert(it2);
        }
        string comb;
        for (auto it3 : setComb) {
            comb = comb.empty() ? it3 : comb + "/" + it3;
        }
        acTypeCrewCombs.insert(comb);
    }

    ICPUtility::basResLimitList.clear();
    for (auto base : ICPUtility::basBaseStrList) {
        parallel_for_each(acTypeCrewCombs.begin(), acTypeCrewCombs.end(), [&](string acTypeCrewComb) {
            for (time_t curDate = ICPUtility::bgnDate; curDate <= ICPUtility::endDate;
                 curDate = curDate + DAY_SECONED_DEFINE) {
                int hrCnt = 0;
                for (auto it3 : _hrCrewMap) {
                    if (it3.second->getBase() != base)
                        continue;
                    bool isMatch = false;
                    for (auto it4 : it3.second->getPersonTechInfo()) {
                        if (acTypeCrewComb.find(it4.acTypeCrew) != string::npos) {
                            isMatch = true;
                            break;
                        }
                    }
                    if (!isMatch)
                        continue;
                    bool isSch = false;
                    for (auto it4 : it3.second->getPersonSchedule()) {
                        if (it4.fromDate <= curDate && curDate <= it4.toDate) {
                            isSch = true;
                            break;
                        }
                    }
                    if (isSch)
                        continue;
                    hrCnt++;
                }
                BasResLimit* resLimit = new BasResLimit(curDate, base, acTypeCrewComb, hrCnt * 3.16 / 6.0);
                // 获取互斥锁
                std::unique_lock<std::mutex> lock(mtx);
                // 访问共享资源
                ICPUtility::basResLimitList.push_back(resLimit);
                // 释放互斥锁
                lock.unlock();
            }
        });
    }
    // if (!ICPUtility::isDebug)
    //{
    //	cout << "BASE,DATE,ACTYPECREWS,CNT"<< endl;
    //	for (auto it : ICPUtility::basResLimitList)
    //	{
    //		cout << it->getBase() << "," <<
    // getDateStr(it->getFlightDate())<<
    //"," << it->getAcTypeCrews() <<  "," << it->getDailyCrewCnt() * 6 / 3.16 <<
    // endl;
    //	}
    // }
}

void ICPService::genAcTypeCrewComb(const vector<std::string>& acTypeCrews, int N, std::vector<string>& combs,
                                   string current) {
    if (N == 0) {
        combs.push_back(current);
        return;
    }

    for (const string& acTypeCrew : acTypeCrews) {
        string newCur = current.empty() ? acTypeCrew : current + "/" + acTypeCrew;
        genAcTypeCrewComb(acTypeCrews, N - 1, combs, newCur);
    }
}

void ICPService::initNodeList() {
    time_t bgnDate = max(ICPUtility::bgnDate - ICPUtility::maxDaysInPairing * DAY_SECONED_DEFINE + DAY_SECONED_DEFINE,
                         ICPUtility::dummyBgnDate) -
                     DAY_SECONED_DEFINE;
    time_t endDate = min(ICPUtility::endDate + ICPUtility::maxDaysInPairing * DAY_SECONED_DEFINE - DAY_SECONED_DEFINE,
                         ICPUtility::dummyEndDate) +
                     DAY_SECONED_DEFINE;

    for (int theDate = bgnDate; theDate <= endDate; theDate = theDate + DAY_SECONED_DEFINE) {
        for (int j = 0; j < _airportList.size(); j++) {
            if (!_airportList[j]->fsbOvernight()) {
                continue;
            }

            ICPNode* newNode = new ICPNode(theDate, _airportList[j]);
            _nodeList.push_back(newNode);
            for (int k = 0; k < _dutyList.size(); k++) {
                if (_dutyList[k]->getDate() == newNode->getDate() && _dutyList[k]->getDep() == newNode->getAirport()) {
                    newNode->pushOutDuty(_dutyList[k]);
                    _dutyList[k]->setStartNode(newNode);
                }

                if (_dutyList[k]->getDate() + DAY_SECONED_DEFINE == newNode->getDate() &&
                    _dutyList[k]->getArr() == _airportList[j]) {
                    _dutyList[k]->setEndNode(newNode);
                }
            }
        }
    }

    // for (int i = 0; i < _nodeList.size(); i++)
    //{
    //	_nodeList[i]->print();
    // }
}

void ICPService::genDutyList() {
    vector<SchDuty*> baseDutyList = genDutyListBase();
    cout << "Base duty size is " << baseDutyList.size() << endl;

    vector<SchDuty*> restDutyList = genDutyListRest();
    cout << "Rest duty size is " << restDutyList.size() << endl;

    _dutyList = baseDutyList;
    // if (!ICPUtility::isDebug)
    { _dutyList.insert(_dutyList.end(), restDutyList.begin(), restDutyList.end()); }
    cout << "Total duty size is " << _dutyList.size() << endl;

    computeDutyCost();

    // 统计没有组到duty中的航段，这些班属于漏班，应该越少越好，最好不要有
    vector<SchLeg*> brokenLegs;
    for (int i = 0; i < _legList.size(); i++) {
        if (_legList[i]->getLegType() == LEGTYPE::LEG_BACKUP)
            continue;
        if (_legList[i]->isTarget()) {
            bool found = false;
            for (int j = 0; j < _dutyList.size(); j++) {
                if (_dutyList[j]->containLeg(_legList[i])) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                brokenLegs.push_back(_legList[i]);
            }
        }
    }

    cout << "无法组到DUTY中的航段 " << brokenLegs.size() << "个" << endl;
    for (int i = 0; i < brokenLegs.size(); i++) {
        brokenLegs[i]->print();
    }
}

vector<SchDuty*> ICPService::genDutyListBase() {
    sortLegList();

    for (int i = 0; i < _legList.size(); i++) {
        for (int j = i + 1; j < _legList.size(); j++) {
            if (ICPRule::CheckRuleOutLeg(_legList[i], _legList[j])) {
                _legList[i]->pushOutLeg(_legList[j]);
            }
        }
    }

    /* gen duty */
    // for (int i = 0; i < _legList.size(); i++) {
    //     // gen regular duty
    //     if (!_legList[i]->getDep()->fsbOvernight()) {
    //         continue;
    //     }
    //     if (_legList[i]->getLegType() == LEGTYPE::LEG_BACKUP) {
    //         continue;
    //     }
    //     SchDuty* newDuty = new SchDuty(_legList[i]->getDate(), 1);
    //     genDutyList(newDuty, _legList[i]);
    // }
    //  for_each(_dutyList.begin(), _dutyList.end(), [&](SchDuty* duty) { duty->init(); });

    parallel_for_each(_legList.begin(), _legList.end(), [&](SchLeg* leg) {
        if (!leg->getDep()->fsbOvernight()) {
            return;
        }
        if (leg->getLegType() == LEGTYPE::LEG_BACKUP) {
            return;
        }

        SchDuty* newDuty = new SchDuty(leg->getDate(), 1);
        genDutyList(newDuty, leg);
    });
    parallel_for_each(_dutyList.begin(), _dutyList.end(), [&](SchDuty* duty) { duty->init(); });

    vector<SchDuty*> tmpList = _dutyList;
    _dutyList.clear();
    return tmpList;
}

vector<SchDuty*> ICPService::genDutyListRest() {
    vector<SchDuty*> restDutyList;
    for (int i = 0; i < _airportList.size(); i++) {
        // gen rest duty
        if (!_airportList[i]->fsbOvernight()) {
            continue;
        }
        // 海口和北京不能作为REST_DUTY
        if (_airportList[i]->getCode3() == "PEK") {
            continue;
        }
        // if (_airportList[i]->getCode3() == "HAK")
        //{
        //	continue;
        // }
        for (time_t theDate = ICPUtility::dummyBgnDate; theDate <= ICPUtility::dummyEndDate;
             theDate = theDate + DAY_SECONED_DEFINE) {
            SchDuty* newDuty = new SchDuty(theDate, 1);
            newDuty->setType(DUTY_REST);
            newDuty->setAirport(_airportList[i]);
            restDutyList.push_back(newDuty);
        }
    }
    return restDutyList;
}

void ICPService::genDutyList(SchDuty* pDuty, SchLeg* pLeg) {
    if (pDuty->getLegSize() >= ICPUtility::maxLegNumInDuty) {
        return;
    }
    if (pLeg->getLegType() == LEGTYPE::LEG_BACKUP) {
        return;
    }
    pDuty->pushLeg(pLeg);

    if (pDuty->getArr()->fsbOvernight()) {
        pDuty->init();
        if (ICPRule::CheckRuleDutyAll(pDuty)) {
            // 获取互斥锁
            std::unique_lock<std::mutex> lock(mtx);

            // 访问共享资源
            _dutyList.push_back(pDuty->clone());

            // 释放互斥锁
            lock.unlock();
        }
    }

    vector<SchLeg*> legs = pLeg->getOutLegList();
    for (int i = 0; i < legs.size(); i++) {
        genDutyList(pDuty, legs[i]);
    }

    pDuty->popLeg();
}

void ICPService::computeDutyCost() {
    for (int i = 0; i < _dutyList.size(); i++) {
        _dutyList[i]->computeCost();
    }
}

void ICPService::updateDutyRedCost() {
    for (int i = 0; i < _dutyList.size(); i++) {
        _dutyList[i]->computeRedCost();
    }
    for (int i = 0; i < _pairingListPattern.size(); i++) {
        for (int j = 0; j < _pairingListPattern[i]->getDutyList().size(); j++) {
            _pairingListPattern[i]->getDutyList()[j]->computeRedCost();
        }
    }
}

vector<SchPairing*> ICPService::genPairingListByDuty() {
    vector<SchPairing*> result;
    for (auto duty : _dutyList) {
        if (duty->getDate() < ICPUtility::bgnDate)
            continue;
        if (duty->getDate() > ICPUtility::endDate)
            continue;
        if (duty->getType() == DUTYTYPE::DUTY_REST)
            continue;
        if (duty->getFirstNonDeadheadLeg() == NULL)
            continue;
        for (auto cfg : ICPUtility::pairingConfigList) {
            if (cfg->getBgnTerminal() == duty->getDep()->getCode3() &&
                cfg->getEndTerminal() == duty->getArr()->getCode3()) {
                SchPairing* pairing = new SchPairing(cfg->getBaseCode());
                pairing->insertFrontDuty(duty);
                pairing->computeCost();
                pairing->computeRedCost();
                if (ICPRule::CheckRulePairingAll(pairing)) {
                    result.push_back(pairing);
                }
                break;
            }
        }
    }
    return result;
}

void ICPService::genPairingListByPattern() {
    _pairingListPattern.clear();
    for (auto it : ICPUtility::lstPattern) {
        auto voyage = it->getVoyage(); // 【/0A7853URCLHW-A7853LHWNKG/1A7854NKGLHW-A7854LHWURC/】
        voyage = voyage.substr(1, voyage.length() - 2);
        for (time_t i = ICPUtility::bgnDate; i <= ICPUtility::endDate; i = i + DAY_SECONED_DEFINE) {
            vector<SchDuty*> dutys;
            for (auto dutyInfo : splitString(voyage, "/")) {
                auto dayAt = stoi(dutyInfo.substr(0, 1));
                auto flightDate = i + dayAt * DAY_SECONED_DEFINE;
                vector<SchLeg*> legs;
                for (auto legInfo : splitString(dutyInfo.substr(1), "-")) {
                    SchLeg* leg = nullptr;
                    for (int i = 0; i < _legList.size(); i++) {
                        if (_legList[i]->getDate() == flightDate && _legList[i]->getVoyage() == legInfo) {
                            leg = _legList[i];
                            break;
                        }
                    }
                    if (leg == nullptr) {
                        legs.clear();
                        break;
                    }
                    legs.push_back(leg);
                }
                if (legs.empty()) {
                    dutys.clear();
                    break;
                }
                SchDuty* duty = new SchDuty(flightDate, 1);
                duty->setLegList(legs);
                duty->init();
                duty->computeCost();
                dutys.push_back(duty);
            }

            if (!dutys.empty()) {
                string baseCode = ICPUtility::homeBase;
                if (dutys[0]->getDep()->isBase()) {
                    baseCode = dutys[0]->getDep()->getCode3();
                } else if (dutys[0]->getArr()->isBase()) {
                    baseCode = dutys[0]->getArr()->getCode3();
                }
                SchPairing* pairing = new SchPairing(baseCode);
                pairing->setDutyList(dutys);
                pairing->computeCost();
                pairing->computeRedCost();

                _pairingListPattern.push_back(pairing);
            }
        }
    }
}

void ICPService::genBetterPairingList() {
    _betterPairingList.clear();

    genBetterPairingListBase();

    for (int i = 0; i < _betterPairingList.size(); i++) {
        if (!ICPRule::CheckRulePairingAll(_betterPairingList[i])) {
            delete _betterPairingList[i];
            _betterPairingList.erase(_betterPairingList.begin() + i);
            i--;
        }
    }

    sort(_betterPairingList.begin(), _betterPairingList.end(), SchPairing::cmpByRedCost);
    for (int i = 0; i < _betterPairingList.size(); i++) {
        if (_betterPairingList[i]->getDutySize() > 6) {
            cout << "Error duty" << endl;
            _betterPairingList[i]->print();
            exit(0);
        }
    }

    if (ICPUtility::isExpModel) {
        cout << endl << ">>> subproblem better pairing size: " << _betterPairingList.size() << endl;
        if (!_betterPairingList.empty()) {
            //_betterPairingList.front()->print();
        }
        cout << endl;
    }
}

void ICPService::genBetterPairingListBase() {
    try {
        if (ICPUtility::maxFlyDayInPairing <= 1) {
            cout << "Warning: ICPService::genBetterPairingList. "
                    "ICPUtility::maxDutySizeInPairing = 1"
                 << endl;
            // exit(0);
        }

        time_t bgnDate =
            max(ICPUtility::bgnDate - ICPUtility::maxFlyDayInPairing * DAY_SECONED_DEFINE + DAY_SECONED_DEFINE,
                ICPUtility::dummyBgnDate) -
            DAY_SECONED_DEFINE;
        time_t endDate =
            min(ICPUtility::endDate + ICPUtility::maxFlyDayInPairing * DAY_SECONED_DEFINE - DAY_SECONED_DEFINE,
                ICPUtility::dummyEndDate) +
            DAY_SECONED_DEFINE;
        vector<PairingPath*> paths;
        // 国内任务环按配置天数走，最多4天
        for (time_t i = bgnDate; i <= endDate; i = i + DAY_SECONED_DEFINE) {
            for (int j = 1; j <= ICPUtility::maxFlyDayInPairing; j++) {
                time_t bgnNodeDate = i;
                time_t endNodeDate = i + j * DAY_SECONED_DEFINE;
                for (int m = 0; m < ICPUtility::pairingConfigList.size(); m++) {
                    if (ICPUtility::pairingConfigList[m]->getMaxPairingDays() >= j) {
                        ICPNode* bgnNode = NULL;
                        ICPNode* endNode = NULL;
                        for (int n = 0; n < _nodeList.size(); n++) {
                            if (bgnNodeDate == _nodeList[n]->getDate() &&
                                _nodeList[n]->getAirport()->getCode3() ==
                                    ICPUtility::pairingConfigList[m]->getBgnTerminal()) {
                                bgnNode = _nodeList[n];
                            }

                            if (endNodeDate == _nodeList[n]->getDate() &&
                                _nodeList[n]->getAirport()->getCode3() ==
                                    ICPUtility::pairingConfigList[m]->getEndTerminal()) {
                                endNode = _nodeList[n];
                            }
                        }

                        if (bgnNode != NULL && endNode != NULL) {
                            auto base = ICPUtility::pairingConfigList[m]->getBaseCode();
                            auto path = new PairingPath(base, bgnNode, endNode, false);
                            paths.push_back(path);
                        }
                    }
                }
            }
        }
        // 国际任务环按配置天数走，最多7天
        for (time_t i = bgnDate; i <= endDate; i = i + DAY_SECONED_DEFINE) {
            for (int j = 1; j <= 7; j++) {
                time_t bgnNodeDate = i;
                time_t endNodeDate = i + j * DAY_SECONED_DEFINE;
                for (int m = 0; m < ICPUtility::pairingConfigList.size(); m++) {
                    if (ICPUtility::pairingConfigList[m]->getMaxPairingDaysI() >= j) {
                        ICPNode* bgnNode = NULL;
                        ICPNode* endNode = NULL;
                        for (int n = 0; n < _nodeList.size(); n++) {
                            if (bgnNodeDate == _nodeList[n]->getDate() &&
                                _nodeList[n]->getAirport()->getCode3() ==
                                    ICPUtility::pairingConfigList[m]->getBgnTerminal()) {
                                bgnNode = _nodeList[n];
                            }

                            if (endNodeDate == _nodeList[n]->getDate() &&
                                _nodeList[n]->getAirport()->getCode3() ==
                                    ICPUtility::pairingConfigList[m]->getEndTerminal()) {
                                endNode = _nodeList[n];
                            }
                        }

                        if (bgnNode != NULL && endNode != NULL) {
                            auto base = ICPUtility::pairingConfigList[m]->getBaseCode();
                            auto path = new PairingPath(base, bgnNode, endNode, true);
                            paths.push_back(path);
                        }
                    }
                }
            }
        }

        if (!ICPUtility::isDebug) {
            parallel_for_each(paths.begin(), paths.end(), [&](auto path) {
                vector<SchPairing*> betterPairingList = genBetterPairingList(path);
                // 获取互斥锁
                std::unique_lock<std::mutex> lock(mtx);
                _betterPairingList.insert(_betterPairingList.end(), betterPairingList.begin(), betterPairingList.end());
                // 释放互斥锁
                lock.unlock();
            });
        } else {
            for (auto path : paths) {
                auto baseCode = path->getBaseCode();
                auto startNode = path->getStartNode();
                auto endNode = path->getEndNode();
                auto isI = path->isI();
                if (!(startNode->getDate() == convertToDate("2025-02-20") &&
                      startNode->getAirport()->getCode3() == "CAN" &&
                      endNode->getDate() == convertToDate("2025-02-23") &&
                      endNode->getAirport()->getCode3() == "CAN")) {
                    continue;
                }

                auto betterPairingList = genBetterPairingList(path);
                _betterPairingList.insert(_betterPairingList.end(), betterPairingList.begin(), betterPairingList.end());
            }
        }
    } catch (exception e) {
        cout << e.what() << endl;
        exit(0);
    }
}

vector<SchPairing*> ICPService::genBetterPairingList(PairingPath* pairingPath) {
    try {
        auto baseCode = pairingPath->getBaseCode();
        auto startNode = pairingPath->getStartNode();
        auto endNode = pairingPath->getEndNode();
        auto isI = pairingPath->isI();
        vector<ICPNode*> nodes;
        for (int i = 0; i < _nodeList.size(); i++) {
            if (_nodeList[i]->getDate() > startNode->getDate() && _nodeList[i]->getDate() < endNode->getDate()) {
                nodes.push_back(_nodeList[i]);
            }
        }
        sort(nodes.begin(), nodes.end(), ICPNode::cmpByDate);

        nodes.insert(nodes.begin(), startNode);
        nodes.insert(nodes.end(), endNode);

        map<ICPNode*, vector<ICPLabel*>> mapNodeLabels;
        vector<SchPairing*> betterPairingList; // 函数返回值
        set<BasAirport*> nightAirports;        // 过夜机场

        /**********************************HSM***************************************************************/

        ICPLabel* label = new ICPLabel(startNode, NULL, 0, NULL, 0, nightAirports);
        // startNode->pushLabel(label);
        vector<ICPLabel*> labels;
        labels.push_back(label);
        mapNodeLabels.insert(make_pair(startNode, labels));

        /**********************************HSM*************************************************************/
        for (int i = 0; i < nodes.size(); i++) {
            vector<SchDuty*> outDutyList = nodes[i]->getOutDutyList();

            // 任务环第一个duty不能是DUTY_REST
            if (nodes[i] == startNode) {
                for (int j = 0; j < outDutyList.size(); j++) {
                    if (outDutyList[j]->getType() == DUTY_REST) {
                        outDutyList.erase(outDutyList.begin() + j);
                        j--;
                    }
                }
            }

            for (int j = 0; j < outDutyList.size(); j++) {
                auto isExclude = false;
                if (outDutyList[j]->fixedLP()) {
                    isExclude = true;
                } else if (outDutyList[j]->getFirstNonDeadheadLeg() != NULL) {
                    auto firstLeg = outDutyList[j]->getFirstNonDeadheadLeg();
                    if (isI && firstLeg->getDorI() != D_OR_I::I) {
                        isExclude = true;
                    } else if (!isI && firstLeg->getDorI() == D_OR_I::I) {
                        isExclude = true;
                    }
                }
                if (isExclude) {
                    outDutyList.erase(outDutyList.begin() + j);
                    j--;
                }
            }
            vector<ICPLabel*> labelList;
            auto iter1 = mapNodeLabels.find(nodes[i]);
            if (iter1 != mapNodeLabels.end()) {
                labelList = iter1->second;
            }

            for (int j = 0; j < labelList.size(); j++) {
                for (int k = 0; k < outDutyList.size(); k++) {
                    if (labelList[j]->getPrevDuty() == NULL ||
                        labelList[j]->getPrevDuty()->feaOutDuty(outDutyList[k])) {
                        if (!ICPRule::CheckRuleTabuSearch(baseCode, startNode, endNode, labelList[j], outDutyList[k])) {
                            continue;
                        }

                        ICPNode* nextNode = outDutyList[k]->getEndNode();
                        bool nodeFound = false;
                        for (int m = 0; m < nodes.size(); m++) {
                            if (nextNode == nodes[m]) {
                                nodeFound = true;
                                break;
                            }
                        }

                        if (nodeFound) {
                            double profit = getProfit(baseCode, labelList[j], outDutyList[k]);
                            int deadheadCnt = labelList[j]->getDeadheadCnt() + outDutyList[k]->getDeadheadCnt();
                            set<BasAirport*> nightAirports = labelList[j]->getNightAirports();
                            nightAirports.insert(outDutyList[k]->getDep());
                            ICPLabel* nextLabel = new ICPLabel(nextNode, outDutyList[k], profit, labelList[j],
                                                               deadheadCnt, nightAirports);
                            map<ICPNode*, vector<ICPLabel*>>::iterator iter2 = mapNodeLabels.find(nextNode);
                            if (iter2 != mapNodeLabels.end()) {
                                if (!dominateLabel(iter2->second, nextLabel)) {
                                    iter2->second.push_back(nextLabel);
                                }
                            } else {
                                vector<ICPLabel*> labels2;
                                labels2.push_back(nextLabel);
                                mapNodeLabels[nextNode] = labels2;
                            }
                        }
                    }
                }
            }
        }

        vector<ICPLabel*> endLabelList;
        map<ICPNode*, vector<ICPLabel*>>::iterator iter3 = mapNodeLabels.find(endNode);
        if (iter3 != mapNodeLabels.end()) {
            endLabelList = iter3->second;
        }
        for (int i = 0; i < endLabelList.size(); i++) {
            SchPairing* pairing = new SchPairing(baseCode);
            ICPLabel* crtLabel = endLabelList[i];
            while (crtLabel != NULL && crtLabel->getPrevLabel() != NULL) {
                pairing->insertFrontDuty(crtLabel->getPrevDuty());
                crtLabel = crtLabel->getPrevLabel();
            }
            pairing->computeCost();
            pairing->computeRedCost();

            if (abs(pairing->getRedCost() - endLabelList[i]->getProfit()) > 1) {
                cout << "Error reduced Cost !!!" << endl;
                cout << "Pairing Computed Red Cost is " << pairing->getRedCost() << endl;
                cout << "endLabel Red Cost is " << endLabelList[i]->getProfit() << endl;
                pairing->print();
                exit(0);
            }
            if (pairing->getRedCost() > EPSILON) {
                betterPairingList.push_back(pairing);
            } else {
                // 内存释放
                delete (pairing);
                pairing = NULL;
            }
        }

        // 内存释放
        nodes.clear();
        nightAirports.clear();
        for (auto it1 : mapNodeLabels) {
            auto lables = it1.second;
            for (ICPLabel* label : labels) {
                delete (label);
                label = NULL;
            }
            labels.clear();
        }
        mapNodeLabels.clear();

        return betterPairingList;
    } catch (exception e) {
        cout << e.what() << endl;
        exit(0);
    }
}

// 注 dominate俯视
bool ICPService::dominateLabel(vector<ICPLabel*>& pLabelList, ICPLabel* pLabel) {
    for (int m = 0; m < pLabelList.size(); m++) {
        if (pLabelList[m]->dominate(pLabel)) {
            delete pLabel;
            return true;
        }

        if (pLabel->dominate(pLabelList[m])) {
            delete pLabelList[m];
            pLabelList.erase(pLabelList.begin() + m);
            m--;
        }
    }
    return false;
}

double ICPService::getHardAirportScore(vector<BasAirport*> airportList) {
    double score = 0;
    for (int i = 0; i < airportList.size(); i++) {
        if (airportList[i]->getSpLevel() != SP_LEVEL_NIL) {
            score = score + 1.8;
        }
    }

    return score;
}

double ICPService::getProfit(string baseCode, ICPLabel* label, SchDuty* duty) {
    SchPairing* pairing = new SchPairing(baseCode);
    pairing->insertFrontDuty(duty);
    ICPLabel* crtLabel = label;
    while (crtLabel != NULL && crtLabel->getPrevLabel() != NULL) {
        pairing->insertFrontDuty(crtLabel->getPrevDuty());
        crtLabel = crtLabel->getPrevLabel();
    }
    pairing->computeCost();
    pairing->computeRedCost();
    double redCost = pairing->getRedCost();

    delete (pairing);
    pairing = NULL;

    return redCost;
}

vector<SchPairing*> ICPService::genUnSolvePairing() {
    vector<SchPairing*> result;
    for (auto leg : _legList) {
        if (leg->getLegType() != LEG_REGULAR)
            continue;

        if (leg->getDate() >= ICPUtility::bgnDate && leg->getDate() <= ICPUtility::endDate && !leg->fixedLP()) {
            string baseCode = "HAK";
            if (leg->getDep()->isBase()) {
                baseCode = leg->getDep()->getCode3();
            } else if (leg->getArr()->isBase()) {
                baseCode = leg->getArr()->getCode3();
            }
            SchPairing* pairing = new SchPairing(baseCode);

            auto duty = new SchDuty(leg->getDate(), 1);
            duty->pushLeg(leg);
            duty->init();
            pairing->insertFrontDuty(duty);

            result.push_back(pairing);
        }
    }

    return result;
}

vector<SchPairing*> ICPService::genPairingB() {
    vector<SchPairing*> result;
    for (SchLeg* legB : this->getLegList()) {
        if (legB->getLegType() != LEGTYPE::LEG_BACKUP)
            continue;
        int crewId = 0;
        for (auto cfgb : ICPUtility::lstSchConfigB) {
            if (cfgb->getAcTypes().find(legB->getAcTypeCrew()) == string::npos) {
                continue;
            }

            crewId = cfgb->getCrewId();
            break;
        }

        auto duty = new SchDuty(legB->getDate(), 1);
        duty->pushLeg(legB);
        SchPairing* pairing = new SchPairing(legB->getDep()->getCode3());
        pairing->insertFrontDuty(duty);
        pairing->setCrewId(crewId);
        result.push_back(pairing);
    }

    return result;
}
